package com.epam.productstore.action;

import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.transform.Transformer;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.actions.DispatchAction;
import org.jdom.Document;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.jdom.output.XMLOutputter;

import com.epam.productstore.form.ProductForm;
import com.epam.productstore.listener.ContextPathListener;
import com.epam.productstore.lock.Locker;
import com.epam.productstore.transformation.StylesheetCache;
import com.epam.productstore.util.ResourceManager;
import com.epam.productstore.validation.ValidationRule;
import com.epam.productstore.validation.rules.DateRule;
import com.epam.productstore.validation.rules.ModelRule;
import com.epam.productstore.validation.rules.NotEmptyValueRule;
import com.epam.productstore.validation.rules.PriceRule;
import com.epam.productstore.validation.validator.FormValidator;


public class ProductAction extends DispatchAction {
	private static final String XML_PATH;
	private static final String ADD_XSL_PATH;
	private static final String SAVE_XSL_PATH;
	
	private static final String CATEGORY_NAME_PARAMETER = "categoryName";
	private static final String SUBCATEGORY_NAME_PARAMETER = "subcategoryName";
	private static final String PRODUCER_PARAMETER = "producer";
	private static final String MODEL_PARAMETER = "model";
	private static final String DATE_PARAMETER = "date";
	private static final String COLOR_PARAMETER = "color";
	private static final String PRICE_PARAMETER = "price";
	private static final String VALIDATOR_PARAMETER = "formValidator";
	private static final String NOT_IN_STOCK_PARAMETER = "notInStock";
	private static final String CATEGORIES_FORWARD_NAME = "categories";
	
	private static final String SUBCATEGORIES_FORWARD_NAME = "subcategories";
	private static final String GOODS_FORWARD_NAME = "goods";
	private static final String GOODS_METHOD_FORWARD_NAME = "goodsList";
	
	static {
		XML_PATH = ContextPathListener.getContextRealPath() + ResourceManager.getProperty(ResourceManager.XML_PATH);
		ADD_XSL_PATH = ContextPathListener.getContextRealPath() + ResourceManager.getProperty(ResourceManager.ADD_GOOD_XSL_PATH);
		SAVE_XSL_PATH = ContextPathListener.getContextRealPath() + ResourceManager.getProperty(ResourceManager.SAVE_GOOD_XSL_PATH);
	}
	
	public ActionForward categoryList(ActionMapping mapping, ActionForm form, HttpServletRequest request,
									HttpServletResponse response) throws Exception {	
		updateProductForm(form);
		return mapping.findForward(CATEGORIES_FORWARD_NAME);		
	}
	
	public ActionForward subcategoryList(ActionMapping mapping, ActionForm form, HttpServletRequest request,
									HttpServletResponse response) throws Exception {
	
		updateProductForm(form);
		return mapping.findForward(SUBCATEGORIES_FORWARD_NAME);		
	}
	
	public ActionForward goodsList(ActionMapping mapping, ActionForm form, HttpServletRequest request,
									HttpServletResponse response) throws Exception {
	
		updateProductForm(form);
		return mapping.findForward(GOODS_FORWARD_NAME);		
	}
	
	public ActionForward add(ActionMapping mapping, ActionForm form, HttpServletRequest request,
									HttpServletResponse response) throws Exception {
		Transformer transformer = StylesheetCache.newTransformer(ADD_XSL_PATH);
		ProductForm productForm = (ProductForm)form;
		System.out.println(productForm.getCategoryName());
		transformer.setParameter(CATEGORY_NAME_PARAMETER, productForm.getCategoryName());
		transformer.setParameter(SUBCATEGORY_NAME_PARAMETER, productForm.getSubcategoryName());
		Locker.READ_LOCK.lock();
		try{
			transformer.transform(new StreamSource(XML_PATH), new StreamResult(response.getWriter()));
		} finally {
			Locker.READ_LOCK.unlock();
		}
		return null;
	}
	
	public ActionForward saveGoods(ActionMapping mapping, ActionForm form, HttpServletRequest request,
							HttpServletResponse response) throws Exception {
		FormValidator validator = new FormValidator();
		
		ValidationRule notEmptyRule = new NotEmptyValueRule();
		ValidationRule modelRule = new ModelRule();
		ValidationRule priceRule = new PriceRule();
		ValidationRule dateRule = new DateRule();
		
		validator.addValidationRule(PRODUCER_PARAMETER, notEmptyRule);
		validator.addValidationRule(MODEL_PARAMETER, notEmptyRule);
		validator.addValidationRule(MODEL_PARAMETER, modelRule);
		validator.addValidationRule(DATE_PARAMETER, notEmptyRule);
		validator.addValidationRule(DATE_PARAMETER, dateRule);
		validator.addValidationRule(COLOR_PARAMETER, notEmptyRule);
		validator.addValidationRule(PRICE_PARAMETER, notEmptyRule);
		validator.addValidationRule(PRICE_PARAMETER, priceRule);

		Transformer transformer = StylesheetCache.newTransformer(SAVE_XSL_PATH);
	
		transformer.setParameter(VALIDATOR_PARAMETER, validator);
		transformer.setParameter(PRODUCER_PARAMETER, request.getParameter(PRODUCER_PARAMETER));
		transformer.setParameter(MODEL_PARAMETER, request.getParameter(MODEL_PARAMETER));
		transformer.setParameter(DATE_PARAMETER, request.getParameter(DATE_PARAMETER));
		transformer.setParameter(COLOR_PARAMETER, request.getParameter(COLOR_PARAMETER));			
		if( request.getParameter(NOT_IN_STOCK_PARAMETER) != null){
			transformer.setParameter(NOT_IN_STOCK_PARAMETER, true);
		} else {
			transformer.setParameter(PRICE_PARAMETER, request.getParameter(PRICE_PARAMETER));
		}
	
		transformer.setParameter(CATEGORY_NAME_PARAMETER, request.getParameter(CATEGORY_NAME_PARAMETER));
		transformer.setParameter(SUBCATEGORY_NAME_PARAMETER, request.getParameter(SUBCATEGORY_NAME_PARAMETER));

		Writer tempWriter = new StringWriter();
		Locker.READ_LOCK.lock();
		try{
			transformer.transform(new StreamSource(XML_PATH), new StreamResult(tempWriter));
		} finally {
			Locker.READ_LOCK.unlock();
		}
		if(validator.isValidForm()){
			Writer fileWriter;
			Locker.WRITE_LOCK.lock();
			try{
				fileWriter = new FileWriter(XML_PATH);
				fileWriter.write(tempWriter.toString());
				fileWriter.close();
			} finally {
				Locker.WRITE_LOCK.unlock();
			}
			return mapping.findForward(GOODS_METHOD_FORWARD_NAME);
		}else {				
			response.getWriter().write(tempWriter.toString());
			return null;
		}
	}
	
	public ActionForward save(ActionMapping mapping, ActionForm form, HttpServletRequest request,
									HttpServletResponse response) throws Exception {
	
		ProductForm productForm = (ProductForm) form;
		Document document = productForm.getDocument();
		Locker.WRITE_LOCK.lock();
		try {			
			XMLOutputter outputter = new XMLOutputter();
			outputter.output(document, new FileOutputStream(XML_PATH));
			return mapping.findForward(GOODS_FORWARD_NAME);
		} finally {
			Locker.WRITE_LOCK.unlock();
		}		
	}
	
	private void updateProductForm(ActionForm form) throws JDOMException, IOException{
		ProductForm productForm = (ProductForm) form;
		File xmlFile = new File(XML_PATH);
		long xmlLastModified = xmlFile.lastModified();
		if (productForm.getXmlLastModified() < xmlLastModified) {
			SAXBuilder builder = new SAXBuilder();
			Document document = null;
			Locker.READ_LOCK.lock();
			try{
				document = builder.build(XML_PATH);
			} finally {
				Locker.READ_LOCK.unlock();
			}
			productForm.setXmlLastModified(xmlLastModified);
			productForm.setDocument(document);
		}
	}
}
